home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / linux-bo / etherboo.000 / etherboo / etherboot-2.0 / netboot-freebsd / linuxloader.c < prev    next >
C/C++ Source or Header  |  1996-06-01  |  9KB  |  330 lines

  1. /**************************************************************************
  2. Linux loader
  3.  
  4. Author: Markus Gutschke (gutschk@math.uni-muenster.de)
  5.   Date: Sep/95
  6.  
  7. **************************************************************************/
  8.  
  9. #include "netboot.h"
  10.  
  11. #define LINUX_IMAGE_ADDR  ((char *)0x10000L)
  12. #define XTRACMDS          ((char *)0x98000L)
  13. #define LINUX_BOOTSECTOR  ((char *)0x90000L)
  14. #define CMDLINEMAGIC      0xA33F
  15. #define CMDLINE           ((unsigned short *)(LINUX_BOOTSECTOR+0x20))
  16. #define BOOTHEADER        (((boot_header_t *)0x90200L)[-1])
  17. #define SECTOR_SIZE       512
  18. #define MAGIC             0xAA55
  19. #define SETUP_MAGIC       0x5A5AAA55
  20.  
  21. typedef struct {
  22.   unsigned char      filler;
  23.   unsigned char      setup_sects;
  24.   unsigned short int root_flags;
  25.   unsigned short int syssize;
  26.   unsigned short int swap_dev;
  27.   unsigned short int ram_size;
  28.   unsigned short int vid_mode;
  29.   unsigned short int root_dev;
  30.   unsigned short int boot_flag;
  31. } boot_header_t;
  32.  
  33. struct bootp_t bootp_reply;
  34.  
  35. char *linux_add_cmdline(char *s)
  36. {
  37. #ifdef    NETBOOT32
  38.   if (!s) *XTRACMDS = '\000';
  39.   else if (*s) {
  40.     char *ptr = XTRACMDS;
  41.     while (*ptr) ptr++;
  42.     *ptr++ = ' ';
  43.     sprintf(ptr,"%s",s); }
  44.   return(XTRACMDS);
  45. #endif
  46. }
  47.  
  48. #ifdef    NETBOOT32
  49. static int strncmp(const unsigned char *s1,const unsigned char *s2,int n)
  50. {
  51.   while (n--) {
  52.     if (*s1 != *s2) return(*s1 - *s2);
  53.     else if (!*s1) return(0);
  54.     else {s1++; s2++;}}
  55.   return(0);
  56. }
  57.  
  58. static void linux_cmdline(char *cmdline)
  59. {
  60.   char   *s,*d,initargs = 0;
  61.  
  62.   for (s = XTRACMDS; ;) { /* check for parameters to init */
  63.     if ((!*s || *s == ' ') && (initargs&1)) initargs = 2;
  64.     if (!*s) break;
  65.     if (*s == '=') {initargs &= ~1; while (*s && *s != ' ') s++;}
  66.     else if (*s++ != ' ') {
  67.       if (!(initargs&1) && !strncmp(s-1,"vga=",4)) {
  68.     int vga = 0;
  69.     d = s + 3;
  70.     if (!strncmp(d,"ASK",3)) vga = -3;
  71.     else if (!strncmp(d,"EXTENDED",8)) vga = -2;
  72.     else if (!strncmp(d,"NORMAL",6)) vga = -1;
  73.     else {
  74.       if (*d == '-') d++;
  75.       while (*d >= '0' && *d <= '9') { vga = 10*vga+*d-'0'; d++; }
  76.       if (s[3] == '-') vga = -vga; }
  77.     *((unsigned short *)(LINUX_BOOTSECTOR+506)) = vga; }
  78.       initargs |= 1; } }
  79.   for (s = nfsdiskless.root_hostnam;*s&&s[1];s++);
  80.   sprintf(cmdline,
  81.       "%sBOOT_IMAGE=%s%s%s ramdisk=0 nfsroot=%s,rsize=%d,wsize=%d,%s,%s nfsaddrs=%I:%I:%I:%I:%s %s",
  82.       initargs&2 ? "" : "auto ",
  83.       /* htonl(nfsdiskless.root_saddr.sin_addr.s_addr), */
  84.       nfsdiskless.root_hostnam,
  85.       *s == '/' ? "" : "/",
  86.       *kernel == '/' ? kernel + 1 : kernel,
  87.       nfsdiskless.root_hostnam,
  88.       nfsdiskless.root_args.rsize,
  89.       nfsdiskless.root_args.wsize,
  90.       nfsdiskless.root_args.flags & NFSMNT_SOFT ? "soft" : "hard",
  91.       nfsdiskless.root_args.flags & NFSMNT_INT ? "intr" : "nointr",
  92.       arptable[ARP_CLIENT].ipaddr,
  93.       htonl(nfsdiskless.root_saddr.sin_addr.s_addr),
  94.       arptable[ARP_GATEWAY].ipaddr,
  95.       htonl(netmask),
  96.       nfsdiskless.my_hostnam,
  97.       XTRACMDS);
  98.   for (s = d = cmdline; ;) { /* remove multiple space characters */
  99.     if (*s == ' ') {while (s[1] ==  ' ') s++; if (!s[1]) s++;}
  100.     if (!(*d++ = *s++)) break; }
  101.   *((unsigned short *)(LINUX_BOOTSECTOR+504)) = 0;      /* no ramdisk */
  102.   *((unsigned short *)(LINUX_BOOTSECTOR+508)) = 0x00FF; /* mount root on nfs */
  103.   return;
  104. }
  105. #endif
  106.  
  107. int load_linux(int root_mount_port,int swap_mount_port,
  108.            int root_nfs_port,char *kernel_handle)
  109. {
  110. #ifdef    NETBOOT32
  111.   int          err, offset, read_size, count;
  112.   char          *addr,*cmdline;
  113.   
  114.   /* Linux boot sector and setup code has to be loaded to address 0x90000 */
  115.   if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, kernel_handle, 0,
  116.               SECTOR_SIZE,LINUX_BOOTSECTOR)) != SECTOR_SIZE) {
  117.   readerr:
  118.     printf("Unable to read %s: ",kernel);
  119.     nfs_err(err);
  120.   bootmenu:
  121.     longjmp(jmp_bootmenu,1);
  122.   }
  123.   if (BOOTHEADER.boot_flag != MAGIC)
  124.     return(0);
  125.   /* Boot sector contains size information for setup code */
  126.   offset    = SECTOR_SIZE;
  127.   read_size = SECTOR_SIZE;
  128.   count     = BOOTHEADER.setup_sects;
  129.   while (count--) {
  130.     if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, kernel_handle,
  131.             offset, read_size, LINUX_BOOTSECTOR + offset)) !=
  132.     read_size) {
  133.       if (err < 0) {
  134.     goto readerr; }
  135.       goto bootmenu; }
  136.     offset += err; }
  137.   for (count = SECTOR_SIZE-4; *(unsigned int *)(LINUX_BOOTSECTOR-
  138.                         SECTOR_SIZE+offset+count) !=
  139.      SETUP_MAGIC;)
  140.     if (count-- < 0)
  141.       goto bootmenu;
  142.   /* Construct Linux's command line */
  143.   cmdline = LINUX_BOOTSECTOR + offset;
  144.   CMDLINE[0] = CMDLINEMAGIC;
  145.   CMDLINE[1] = cmdline - LINUX_BOOTSECTOR;
  146.   linux_cmdline(cmdline);
  147.   while (*cmdline) putchar(*cmdline++);
  148.   printf("\r\n");
  149.   /* Kernel image will be loaded to address 0x10000; it will automatically
  150.      be relocated to 0x100000 by the setup code */
  151.   read_size = NFS_READ_SIZE;
  152.   count = 16*BOOTHEADER.syssize;
  153.   addr  = LINUX_IMAGE_ADDR;
  154.   printf("Loading compressed kernel image");
  155.   while (count >= 16) {
  156.     if (read_size > count) read_size = count;
  157.     if ((err = nfs_read(ARP_ROOTSERVER, root_nfs_port, kernel_handle,
  158.             offset, read_size, addr)) != read_size) {
  159.       if (err < 0) goto readerr;
  160.       if (read_size-err >= 16)
  161.     goto bootmenu; }
  162.     if (!(offset & 0x3C00)) putchar('.');
  163.     offset += err;
  164.     count  -= err;
  165.     addr += err; }
  166.   /* Linux wants to mount swapspace and rootfilesystem by itself; so unmount */
  167.   /* all mounted NFS filesystems */
  168.   nfs_umountall(ARP_ROOTSERVER, root_mount_port);
  169.   if (arptable[ARP_SWAPSERVER].ipaddr &&
  170.       arptable[ARP_SWAPSERVER].ipaddr != arptable[ARP_ROOTSERVER].ipaddr)
  171.     nfs_umountall(ARP_SWAPSERVER, swap_mount_port);
  172.   /* Linux kernel has to be started in real-mode */
  173.   printf(" \r\nStarting...\r\n");
  174.   start_linux();
  175.   /* printf("*** %s execute failure ***\n",kernel); */
  176.   goto bootmenu;
  177. #endif
  178. }
  179.  
  180. /* Define some structures used by tftp loader */
  181.  
  182. union infoblock
  183. {
  184.     unsigned short s[256];
  185.     unsigned long l[128];
  186.     struct imgheader
  187.     {
  188.         unsigned long magic;
  189.         unsigned char length;
  190.         unsigned char r[3];
  191.         struct { unsigned short bx, ds; } location;
  192.         struct { unsigned short ip, cs; } execaddr;
  193.     } i;
  194. };
  195.  
  196. struct segheader
  197. {
  198.     unsigned char length;
  199.     unsigned char vendortag;
  200.     unsigned char reserved;
  201.     unsigned char flags;
  202.     unsigned long loadaddr;
  203.     unsigned long imglength;
  204.     unsigned long memlength;
  205. };
  206.  
  207. /* The following are static because linux_tftp is called for each block
  208.    and we need to retain info across calls */
  209.  
  210. static enum loadmode { Munknown, Mlinear, Mtagged } mode = Munknown;
  211. static unsigned char    segflags;
  212. static unsigned long    seglen;
  213. static Address        curaddr, last0, last1, execaddr, hdraddr, segaddr;
  214.  
  215. int linux_tftp(unsigned int block, unsigned char *data, int len)
  216. {
  217.     int        i;
  218.  
  219.     if (block == 1)
  220.     {
  221.         union infoblock    *ibp = (union infoblock *)data;
  222.         if (ibp->l[0] == 0x1B031336L)
  223.         {
  224.             /* the apparently unnecessary cast is to avoid a
  225.                bcc bug where the short not promoted as it should be */
  226.             segaddr = (((Address)ibp->i.location.ds) << 4) + ibp->i.location.bx;
  227. #ifdef    NETBOOT32
  228.             bcopy(data, (void *)segaddr, len);
  229. #endif
  230. #ifdef    NETBOOT16
  231.             bcopyf(data, segaddr, len);
  232. #endif
  233.             execaddr = ibp->l[3];
  234.             hdraddr = ibp->l[2];
  235.             last1 = last0 = segaddr + 512;
  236.             segaddr += ((ibp->i.length & 0x0F) << 2)
  237.                 + ((ibp->i.length & 0xF0) >> 2);
  238.             segflags = 0;
  239.             seglen = 0;
  240.             mode = Mtagged;
  241.             return (1);
  242.         }
  243.         else if (ibp->s[255] == 0xAA55)
  244.         {
  245. #ifdef    NETBOOT32
  246.             bcopy(data, (void *)0x7C00, len);
  247. #endif
  248. #ifdef    NETBOOT16
  249.             bcopyf(data, 0x7C00L, len);
  250. #endif
  251.             execaddr = hdraddr = 0x7C00000L;
  252.             curaddr = 0x10000L;
  253.             mode = Mlinear;
  254.             return (1);
  255.         }
  256.         return (0);
  257.     }
  258.     else switch (mode)
  259.     {
  260.     case Mlinear:
  261.         if (len <= 0)
  262.         {
  263. #ifdef    NETBOOT32
  264.             xstart(execaddr, hdraddr, (Address)&bootp_reply);
  265. #endif
  266. #ifdef    NETBOOT16
  267.             xstart(execaddr, hdraddr, &bootp_reply, RELOC>>4);
  268. #endif
  269.             longjmp(jmp_bootmenu, 1);
  270.         }
  271. #ifdef    NETBOOT32
  272.         bcopy(data, (void *)curaddr, len);
  273. #endif
  274. #ifdef    NETBOOT16
  275.         bcopyf(data, curaddr, len);
  276. #endif
  277.         if (curaddr += 512 >= 0x98000L)
  278.             curaddr = 0x100000L;
  279.         break;
  280.     case Mtagged:
  281.         while (seglen == 0)
  282.         {
  283.             struct segheader    sh;
  284.             if (segflags & 0x04)
  285.             {
  286. #ifdef    NETBOOT32
  287.                 xstart(execaddr, hdraddr, (Address)&bootp_reply);
  288. #endif
  289. #ifdef    NETBOOT16
  290.                 xstart(execaddr, hdraddr, &bootp_reply, RELOC>>4);
  291. #endif
  292.                 longjmp(jmp_bootmenu, 1);
  293.             }
  294. #ifdef    NETBOOT32
  295.             sh = *((struct segheader *)segaddr);
  296. #endif
  297. #ifdef    NETBOOT16
  298.             fbcopy(segaddr, &sh, sizeof(struct segheader));
  299. #endif
  300.             seglen = sh.imglength;
  301.             if ((segflags = sh.flags & 0x03) == 0)
  302.                 curaddr = sh.loadaddr;
  303.             else if (segflags == 0x01)
  304.                 curaddr = last1 + sh.loadaddr;
  305.             else if (segflags == 0x02)
  306.                 curaddr = (Address)(memsize() * 1024L + 0x100000L)
  307.                     - sh.loadaddr;
  308.             else
  309.                 curaddr = last0 - sh.loadaddr;
  310.             last1 = (last0 = curaddr) + sh.memlength;
  311.             segflags = sh.flags;
  312.             segaddr += ((sh.length & 0x0F) << 2)
  313.                 + ((sh.length & 0xF0) >> 2);
  314.         }
  315.         i = (seglen > len) ? len : seglen;
  316. #ifdef    NETBOOT32
  317.         bcopy(data, (void *)curaddr, i);
  318. #endif
  319. #ifdef    NETBOOT16
  320.         bcopyf(data, curaddr, i);
  321. #endif
  322.         seglen -= i;
  323.         curaddr += i;
  324.         break;
  325.     case Munknown:
  326.         return (0);
  327.     }
  328.     return (1);
  329. }
  330.